
****************************************************
* Replication (Plan A, central ESGP) — Stata do-file
* Purpose: run baseline & interaction models from merged panel
* Author: (generated by ChatGPT)  Date: 2025-10-15
****************************************************

version 16.0
clear all
set more off

* ====== 0) Set your working directory ======
* >>>>> CHANGE THIS to the folder that contains your files <<<<<
* cd "C:\path\to\your\folder"
* cd "/Users/you/path/to/folder"

* ====== 1) Import merged panel ======
local panelxlsx "data.xlsx"
local panelcsv  "panel_planA.csv"

capture confirm file "`panelxlsx'"
if _rc==0 {
   import excel using "`panelxlsx'", firstrow clear

}
else {
    capture confirm file "`panelcsv'"
    if _rc==0 {
        import delimited using "`panelcsv'", varnames(1) clear
    }
    else {
        di as error "Neither data.xlsx nor panel_planA.csv found in current directory."
        exit 1
    }
}

* Quick sanity checks
capture confirm variable GI
if _rc!=0 {
    di as error "Variable 'GI' not found. Make sure your merged panel has GI."
    exit 2
}
capture confirm variable ESGP
if _rc!=0 {
    di as error "Variable 'ESGP' not found. Make sure your merged panel has ESGP."
    exit 3
}
capture confirm variable year
if _rc!=0 {
    di as error "Variable 'year' not found. Please rename your year column to 'year' (numeric)."
    exit 4
}
capture confirm variable stkcd
if _rc!=0 {
    di as error "Variable 'stkcd' not found. Please rename your firm code column to 'stkcd'."
    exit 5
}

* ====== 2) Basic transforms ======
tostring stkcd, replace force
egen firm = group(stkcd)

* ====== 3) Exclusions per paper ======
* 3.1 Exclude ST/*ST when flags exist (auto-detect variable names containing st/pt)
local stvars ""
ds, has(name "*st*")
local stvars `stvars' `r(varlist)'
ds, has(name "*ST*")
local stvars `stvars' `r(varlist)'
ds, has(name "*pt*")
local stvars `stvars' `r(varlist)'
ds, has(name "*PT*")
local stvars `stvars' `r(varlist)'
local stvars : list uniq stvars

foreach v of local stvars {
    capture confirm numeric variable `v'
    if _rc==0 {
        quietly summarize `v'
        if r(min)>=0 & r(max)<=1 {
            di as txt "Dropping rows with `v'==1 (ST/PT exclusion)"
            drop if `v'==1
        }
    }
}

* 3.2 Exclude Finance & Real Estate by industry NAME if available
local indnamevar ""
ds, has(type string)
local svars `r(varlist)'
foreach v of local svars {
    capture count if ustrregexm(`v',"金融|房地产业")
    if _rc==0 & r(N)>0 {
        local indnamevar "`v'"
        continue, break
    }
}
if "`indnamevar'" != "" {
    di as txt "Excluding Finance/Real Estate using industry name var: `indnamevar'"
    drop if ustrregexm(`indnamevar',"金融|房地产业")
}
else {
    di as txt "No industry-name string variable found for exclusion; skipping name-based filter."
}

* ====== 4) Panel settings & scaling ======
* Turn ESGP into percentage points for readability
capture drop ESGP_pp
gen double ESGP_pp = ESGP*100

xtset firm year

* ====== 5) Baseline model (Firm FE only; identifies national ESGP effect) ======
* GI_it = a + b*ESGP_t + Controls_it + Firm FE + e_it
* Do NOT include year FE here (ESGP varies only by year and is collinear with year FE).
estimates clear
capture noisily xtreg GI c.ESGP_pp c.Size c.Age c.Lev c.ROA c.RD i.SOE c.Board, fe vce(cluster firm)
estimates store FE_base

* ====== 6) Interaction models (Industry FE + Year FE; firm absorbed) ======
* Prefer an industry code variable if present; otherwise encode industry name
capture drop indcode
capture confirm variable 行业代码1
if _rc==0 {
    tostring 行业代码1, replace
    encode 行业代码1, gen(indcode)
}
else if "`indnamevar'" != "" {
    encode `indnamevar', gen(indcode)
}

capture noisily areg GI c.ESGP_pp##c.Slack c.Size c.Age c.Lev c.ROA c.RD i.SOE i.year i.indcode, absorb(firm) vce(cluster firm)
estimates store INT_slack

capture noisily areg GI c.ESGP_pp##c.MEA   c.Size c.Age c.Lev c.ROA c.RD i.SOE i.year i.indcode, absorb(firm) vce(cluster firm)
estimates store INT_mea

* ====== 7) Display results ======
di as result "=== Baseline: Firm FE (no year FE) ==="
estimates display FE_base

di as result "=== Interaction: Slack (Ind FE + Year FE; firm absorbed) ==="
estimates display INT_slack

di as result "=== Interaction: MEA (Ind FE + Year FE; firm absorbed) ==="
estimates display INT_mea

di as txt "Done."
